module Local (Local, nuevoL, nombreL, tipoDeLocalL, agenciasAdheridasL, habituesL, citasL, habituarL, citarEnLocal, localesSensibles, serHabitueGarpa, tiroteadoresEnVano, sePuedeSwingear, besoAbeso)
where

import Tipos
import Persona
import Prospecto
import Cita
import Agencia

data Local =  L Nombre TipoDeLocal | Adherir Agencia Local | Habituar Persona Local | 
		Citar Cita Local deriving (Show)
 

nuevoL  :: Nombre -> TipoDeLocal -> [Agencia] -> Local  
nuevoL n t []		= L n t
nuevoL n t (x:xs) 	=  Adherir x (nuevoL n t xs)
					
nombreL :: Local -> Nombre 
nombreL (L n _)					 =  n
nombreL (Adherir  _ x) 			 = nombreL x
nombreL (Habituar _ x )	 		 = nombreL x
nombreL (Citar    _ x )			 = nombreL x

tipoDeLocalL :: Local -> TipoDeLocal
tipoDeLocalL (L _ t) 			= t
tipoDeLocalL  (Adherir _ x)		= tipoDeLocalL x
tipoDeLocalL  (Habituar _ x)	= tipoDeLocalL x
tipoDeLocalL  (Citar _ x)		= tipoDeLocalL x

agenciasAdheridasL :: Local -> [Agencia]
agenciasAdheridasL (L _ _)        = []
agenciasAdheridasL (Adherir a x ) = a:agenciasAdheridasL x
agenciasAdheridasL (Habituar _ x) =   agenciasAdheridasL x
agenciasAdheridasL (Citar _ x)    =   agenciasAdheridasL x

citasL :: Local -> [Cita]      
citasL (L _ _ )			= []
citasL (Adherir _ x) 	= citasL x
citasL (Habituar _ x)	= citasL x
citasL (Citar c x)		= c:citasL x 

habituesL :: Local -> [Persona]
habituesL (L _ _ ) 			= [] 
habituesL (Adherir _ x)		= habituesL x
habituesL (Habituar h x)	= h:habituesL x
habituesL (Citar _ x)		= habituesL x

habituarL :: Local -> Persona -> Local
habituarL x p = Habituar p x

citarEnLocal :: Local -> Persona -> Persona -> Fecha -> Bool -> Local --los requieres del problema garantizan los invariantes en local
citarEnLocal l p1 p2 f b  = if b then Citar (besarC (nuevaC p1  p2 f)) l else  Citar (nuevaC p1  p2 f) l
							

localesSensibles :: [Local] -> [Local]
localesSensibles [] = []
localesSensibles (x:xs)
						| not (perteneceAListaDeLocales x xs) && esSuperSensible x xs			= x:localesSensibles xs
						| otherwise 															= 	localesSesibles xs

---------------------------------------------------------------------------------------------------------------------------------
--Auxiliares de localesSensibles
						
esSuperSensibleHastaI :: Local -> [Local] -> Bool
esSuperSensibleHastaI l [] _ = True 
esSuperSensibleHastaI l (x:xs) = (citasNoHabitueFinalFeliz l >=  citasNoHabitueFinalFeliz x ) &&  esSuperSensibleHastaI l xs
  
citasNoHabitueFinalFeliz ::Local -> Int 
citasNoHabitueFinalFeliz l 
							| length (citasL l) > 0 		= citasNoHabitueFinalFelizHastaI l (length (citasL l)  - 1)
							| otherwise 					= 0

citasNoHabitueFinalFelizHastaI :: Local -> Int ->Int
citasNoHabitueFinalFelizHastaI l 0 = if not (elem (pretendienteC ((citasL l)!!0)) (habituesL l) ) && not (elem (pretendidoC ((citasL l)!!0)) (habituesL l) ) && huboBesoC ((citasL l)!!0)) then 1 else 0
citasNoHabitueFinalFelizHastaI l i
									|  not (elem (pretendienteC ((citasL l)!!i)) (habituesL l) ) && not (elem (pretendidoC ((citasL l)!!i)) (habituesL l) ) && huboBesoC ((citasL l)!!i))  = 1 + citasNoHabitueFinalFelizHastaI l (i-1)
									|  otherwise 																																		   = citasNoHabitueFinalFelizHastaI l (i-1)
						
perteneceAListaDeLocales :: Local -> [Locales] -> Bool  
perteneceAListaDeLocales _ [] = False  
perteneceAListaDeLocales l (x:xs) =  localesIgualitos l x ||  perteneceAListaDeLocales l xs

localesIgualitos :: Local -> Local -> Bool
localesIgualitos l1 l2 = (nombreL l1 == nombreL l2) && (tipoDeLocalL l1 == tipoDeLocalL l2) && (mismasAgencias (agenciasAdheridasL l1) (agenciasAdheridasL l2)) && ( mismos (habituesL l1) (habituesL l2) )  && (mismos (citasL l1) (citasL l2)  ) 

mismasAgencias :: [Agencia] -> [Agencia] -> Bool
mismasAgencias a1 a2 = ( perteneceAgenciasHastaI a1 (length a1 - 1) a2 ) && (perteneceAgenciasHastaI a2 (length a2 - 1) a1)
 
perteneceAgenciasHastaI :: [Agencia] -> Int -> [Agencia] -> Bool
perteneceAgenciasHastaI a1 0 a2 = perteneceAUnaAgencia (a1 !! 0) a2
perteneceAgenciasHastaI a1 i a2 = perteneceAUnaAgencia (a1 !! i) a2  && perteneceAgenciasHastaI a1 (i-1) a2

perteneceAUnaAgencia :: Agencia -> [Agencia] -> Bool
perteneceAUnaAgencia _ [] = False 
perteneceAUnaAgencia a (x:xs) =  agenciasIgualesA a x  ||  perteneceAUnaAgencia a xs

---------------------------------------------------------------------------------------------------------------------------------
serHabitueGarpa :: Local -> [Persona]
serHabitueGarpa l 
					| length (habituesL l) > 0              = sinRepetidos (serHabitueGarpaHastaI l (length (habituesL l) - 1))
					| otherwise 							= []
---------------------------------------------------------------------------------------------------------------------------------
--Auxiliares de serHabitueGarpa:

sinRepetidos :: [Persona] -> [Persona]
sinRepetidos [] = []
sinRepetidos (x:xs)
					|elem x xs	 		= sinRepetidos xs
					|otherwise 			= x:sinRepetidos xs

serHabitueGarpaHastaI :: Local -> Int -> [Persona] --recorre los habitues del local hasta el iesimo tales que en una cita besaron y arma una lista con ellos.
serHabitueGarpaHastaI l 0 = if tuvoCitaExitosa l ((habituesL l)!!0) then ( (habituesL l)!!0 ):[] else []
serHabitueGarpaHastaI l i 

						| tuvoCitaExitosa l ((habituesL l)!! i) 		= ((habituesL l)!! i ) : serHabitueGarpaHastaI l (i-1)						
						| otherwise 									= serHabitueGarpaHastaI l (i-1)
						
tuvoCitaExitosa :: Local -> Persona -> Bool
tuvoCitaExitosa l p  
						| length (citasL l) > 0 			= tuvoCitaExitosaHastaI l p (length (citasL l) - 1)
						| otherwise 						= False 
				
tuvoCitaExitosaHastaI :: Local -> Persona -> Int -> Bool --recorre las citas del local hasta la iesima y verifica se es exitosa o no
tuvoCitaExitosaHastaI l p 0 =   ((p == pretendidoC ((citasL l) !! 0 )  || p == pretendienteC ((citasL l) !! 0 )) && huboBesoC ( (citasL l) !! 0 ) )
tuvoCitaExitosaHastaI l p i =   ((p == pretendidoC ((citasL l) !! i )  || p == pretendidoC ((citasL l) !! i )) && huboBesoC ( (citasL l) !! i ) ) || tuvoCitaExitosaHastaI l p (i -1)
---------------------------------------------------------------------------------------------------------------------------------

tiroteadoresEnVano :: Local -> [Persona]
tiroteadoresEnVano l = if length (citasL l) > 0 then sinRepetidos (tiroteadoresEnVanoHastaI l (length (citasL l) - 1)) else []
---------------------------------------------------------------------------------------------------------------------------------
--Auxiliares de tiroteadoresEnVano:

tiroteadoresEnVanoHastaI :: Local -> Int-> [Persona]  --devuelve la lista pretendientes con mas rebotes hasta la cita iesima
tiroteadoresEnVanoHastaI l 0 = if  tiroteadorEnVano l (pretendienteC ((citasL l)!!0)) then pretendienteC ((citasL l)!!0):[] else []
tiroteadoresEnVanoHastaI l i  
								| tiroteadorEnVano l (pretendienteC ((citasL l)!!i)) =  pretendienteC ((citasL l)!!i):tiroteadoresEnVanoHastaI l (i-1)
								| otherwise 										 =  tiroteadoresEnVanoHastaI l (i - 1) 

tiroteadorEnVano :: Local -> Persona -> Bool  --devuelve verdadero si la persona del parametro fue la mas rebotada en las citas de la agencia  
tiroteadorEnVano l p = tiroteadorEnVanoHastaCitaI l p (length (citasL l) - 1)								
						
tiroteadorEnVanoHastaCitaI :: Local -> Persona -> Int -> Bool  --devuelve verdadero si la persona del parametro tuvo mas rebotes como pretendiente hasta la cita iesima de la agencia
tiroteadorEnVanoHastaCitaI l p 0 = rebotes l p  >= rebotes l (pretendienteC ((citasL l)!!0))
tiroteadorEnVanoHastaCitaI l p i = (rebotes l p  >= rebotes l (pretendienteC ((citasL l)!!i)) )  && tiroteadorEnVanoHastaCitaI l p (i-1)

rebotes :: Local -> Persona -> Int         --devuelve la cantidad de citas en las que reboto la persona del parametro
rebotes l p = length (citasEnCitas (citasL l) p)

citasEnCitas :: [Cita] ->Persona -> [Cita] --de una lista de citas devuelve las citas en los que el pretendiente coincide con el parametro de entrada y no beso
citasEnCitas [] p = []
citasEnCitas (x:xs) p 
						| (p == pretendienteC x)&& not (huboBesoC x)			= x:citasEnCitas xs p
						| otherwise 											= citasEnCitas xs p
-----------------------------------------------------------------------------------

sePuedeSwingear :: Local -> Int -> Dia -> Bool
sePuedeSwingear  l 0 d = conLaPosibilidadDeSwingear ((citasL l)!! 0)  l (length (citasL l) - 1)
sePuedeSwingear  l i d = conLaPosibilidadDeSwingear ((citasL l)!! i)  l (length (citasL l) - 1)  || sePuedeSwingear l (i-1) d

puedenSwingearHastaLaCitaI :: Cita -> Local -> Int -> Dia -> Bool
puedenSwingearHastaLaCitaI c xs 0 d = if  c /= citasL l !! 0 conLaPosibilidadDeSwingear c (citasL l !! 0) d && seDanEntreEllos l c (citasL l !! 0) else False
puedenSwingearHastaLaCitaI c l i d 
						| c /= citasL l !! i =  conLaPosibilidadDeSwingear c (citasL l !! 0) d  && seDanEntreEllos l c (citasL l !! i) || puedenSwingearHastaLaCitaI c l (i-1) d
						| otherwise 		 =  puedenSwingearHastaLaCitaI c l (i-1) d
						
conLaPosibilidadDeSwingear :: Cita -> Cita -> Dia -> Bool
conLaPosibilidadDeSwingear c1 c2 d = fechaC c1 == Dia && fechaC c1  == fechaC c2 && swingers c1 c2


swingers :: Cita -> Cita -> Bool
swingers c1 c2 = swinger (pretendienteC c1)  && swinger (pretendidoC c1) && swinger (pretendienteC c2)  && swinger (pretendidoC c2)

swinger :: Persona -> Bool 
swinger p = elem Swinger (gustosP p)

leDa :: Local -> Persona -> Persona -> Bool






	